package com.cdzs.twocamera;

import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.Surface;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;

import com.cdzs.twocamera.constant.Constant;
import com.cdzs.twocamera.myinterface.NettyListener;
import com.cdzs.twocamera.tcp.NettyClient;
import com.cdzs.twocamera.util.ArrayMergeUtil;
import com.cdzs.twocamera.util.ByteUtil;
import com.cdzs.twocamera.util.DateFormatUtil;
import com.cdzs.twocamera.util.NumberUtil;
import com.cdzs.twocamera.util.TcpAssembleUtil;
import com.cdzs.twocamera.util.WriteLogUtil;
import com.cdzs.twocamera.widget.SimpleUVCCameraTextureView;
import com.serenegiant.common.BaseActivity;
import com.serenegiant.usb.DeviceFilter;
import com.serenegiant.usb.IButtonCallback;
import com.serenegiant.usb.IFrameCallback;
import com.serenegiant.usb.IStatusCallback;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.UVCCamera;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import timber.log.Timber;

public class MainActivityTexture extends BaseActivity implements NettyListener {

    private static final String TAG = "MainActivityTexture";

    private final Object mSync = new Object();
    // 为了访问 USB、USB 摄像头,自定义一个监听器
    private USBMonitor mUSBMonitor;

    private UVCCamera mUVCCamera;
    private UVCCamera mUVCCameraInfrared;

    private SimpleUVCCameraTextureView mUVCCameraView;
    private SimpleUVCCameraTextureView mUVCCameraViewInfrared;

    private Surface mPreviewSurface;
    private Surface mPreviewSurfaceInfrared;

    private List<UsbDevice> mUsbDeviceList;
    private boolean isDettach = false;


    private ImageView mImageView;
    private NetworkReceiver receiver;
    private ScheduledExecutorService mScheduledExecutorService;
    private byte[] heartBeatBytes;
    private byte[] picDataBytes;
    private int personIdIndex;
    private int personNameIndex;
    private int dataLength = 0;
    private byte[] data = new byte[0];
    private Handler handler = new Handler();
    private Bitmap receiveBitmap;

    /**
     * 标记图片是否接收完成，接收完成之后，在发送最新的一帧到服务器
     */
    private boolean isReceived = true;
    private ByteArrayOutputStream baos;
    private byte[] picBytes;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.d(TAG, "onCreate: 程序启动时间   " + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhms));
        Log.d(TAG, "onCreate: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "m");
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        Log.d(TAG, "onCreate: " + activityManager.getMemoryClass());

        Window window = getWindow();
        //隐藏标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        //隐藏状态栏、定义全屏参数
        int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
        //设置当前窗体为全屏显示
        window.setFlags(flag, flag);

        setContentView(R.layout.activity_main);

        mImageView = findViewById(R.id.mImageView);

        receiver = new NetworkReceiver();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);

        NettyClient.getInstance().setListener(this);

        connect();

        // 自定义心跳，每隔20秒向服务器发送心跳包
        mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        // 线程池中发心跳包
        mScheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {

                heartBeatBytes = ArrayMergeUtil.byteMergerAll(
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.NET_HEADER_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(16)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt())
                );

                NettyClient.getInstance().sendMsgToServer(heartBeatBytes, new ChannelFutureListener() {    //3
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        if (future.isSuccess()) {                //4
                            Timber.d("Write heartbeat successful");

                        } else {
                            Timber.e("Write heartbeat error");
                            WriteLogUtil.writeLogByThread("heartbeat error");
                        }
                    }
                });
            }
        }, 3, 3, TimeUnit.SECONDS);

        //sendPicDataPackage();

        mUVCCameraView = findViewById(R.id.UVCCameraTextureView);
        mUVCCameraViewInfrared = findViewById(R.id.UVCCameraTextureViewInfrared);

        // 设置预览默认宽高比
        mUVCCameraView.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraViewInfrared.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);

        mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
    }

    @Override
    protected void onStart() {
        super.onStart();

        // 同步方法、获取访问 USB 的权限、注册之后，会检测一次 USB 是否 attach
        mUSBMonitor.register();

        // 获取 USB 设备的列表
        updateDevices();

        synchronized (mSync) {
            if (mUVCCamera != null) {
                mUVCCamera.startPreview();
            }

            if (mUVCCameraInfrared != null) {
                mUVCCameraInfrared.startPreview();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    /**
     * 更新设备列表
     * 获取设备列表，该列表不可更改
     */
    public void updateDevices() {
        //下面注释代码表示在控制台打印连接设备列表
        //mUSBMonitor.dumpDevices();
        final List<DeviceFilter> filter = DeviceFilter.getDeviceFilters(this, com.serenegiant.uvccamera.R.xml.device_filter);
        mUsbDeviceList = mUSBMonitor.getDeviceList(filter.get(0));

        for (int i = 0; i < mUsbDeviceList.size(); i++) {
            Log.d(TAG, "updateDevices: " + String.format("UVC Camera:(%x:%x:%s)", mUsbDeviceList.get(i).getVendorId(), mUsbDeviceList.get(i).getProductId(), mUsbDeviceList.get(i).getDeviceName()));
            Log.d(TAG, "run: " + mUsbDeviceList.get(i).getProductId());
        }

//        // 判断传入 USB 设备权限、处理连接、绑定USB设备处理模块的处理模块
//        // 0 红外摄像头
//        // 1 自带摄像头
//        // 2 可见光摄像头
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(1000);//休眠3秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int i = 0; i < mUsbDeviceList.size(); i++) {
                    // 大摄像头---可见光
                    // 大摄像头---红外
                    // 小摄像头----可见光
                    // 小摄像头----红外
                    if (mUsbDeviceList.get(i).getProductId() == 25446
                            || mUsbDeviceList.get(i).getProductId() == 8499
                            || mUsbDeviceList.get(i).getProductId() == 33291
                            || mUsbDeviceList.get(i).getProductId() == 13180) {
                        mUSBMonitor.requestPermission(mUsbDeviceList.get(i));
                    }
                }
            }
        }.start();
    }

    @Override
    protected void onStop() {
        synchronized (mSync) {
            if (mUVCCamera != null) {
                mUVCCamera.stopPreview();
            }
            if (mUVCCameraInfrared != null) {
                mUVCCameraInfrared.stopPreview();
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.unregister();
            }
        }
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        synchronized (mSync) {
            releaseCamera();
            if (mToast != null) {
                mToast.cancel();
                mToast = null;
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.destroy();
                mUSBMonitor = null;
            }
        }
        mUVCCameraView = null;
        mUVCCameraViewInfrared = null;

        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
        shutdown();
        NettyClient.getInstance().setReconnectNum(0);
        NettyClient.getInstance().disconnect();

        Log.d(TAG, "onCreate: 程序结束时间   " + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhms));

        super.onDestroy();
    }

    // 关闭线程池
    private void shutdown() {
        if (mScheduledExecutorService != null) {
            mScheduledExecutorService.shutdown();
            mScheduledExecutorService = null;
        }
    }

    private Toast mToast;

    /**
     * 可见光 USB 设备监听
     */
    private final USBMonitor.OnDeviceConnectListener mOnDeviceConnectListener = new USBMonitor.OnDeviceConnectListener() {

        @Override
        public void onAttach(final UsbDevice device) {
            Log.d(TAG, "onAttach: 可见光--插入");
            if (isDettach) {
                isDettach = false;
                updateDevices();
            }
        }

        @Override
        public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) {

            Log.d(TAG, "onConnect: 可见光--连接");

            // 释放 Camera 资源,释放 Camera 和 surface
            releaseCamera();

            queueEvent(new Runnable() {
                @Override
                public void run() {

                    // 摄像头---可见光
                    if (device.getProductId() == 8499 || device.getProductId() == 25446) {
                        final UVCCamera camera = new UVCCamera();
                        camera.open(ctrlBlock);
                        camera.setStatusCallback(new IStatusCallback() {
                            @Override
                            public void onStatus(final int statusClass, final int event, final int selector, final int statusAttribute, final ByteBuffer data) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        final Toast toast = Toast.makeText(MainActivityTexture.this, "onStatus(statusClass=" + statusClass
                                                + "; " +
                                                "event=" + event + "; " +
                                                "selector=" + selector + "; " +
                                                "statusAttribute=" + statusAttribute + "; " +
                                                "data=...)", Toast.LENGTH_SHORT);
                                        synchronized (mSync) {
                                            if (mToast != null) {
                                                mToast.cancel();
                                            }
                                            toast.show();
                                            mToast = toast;
                                        }
                                    }
                                });
                            }
                        });
                        camera.setButtonCallback(new IButtonCallback() {
                            @Override
                            public void onButton(final int button, final int state) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        final Toast toast = Toast.makeText(MainActivityTexture.this, "onButton(button=" + button + "; " +
                                                "state=" + state + ")", Toast.LENGTH_SHORT);
                                        synchronized (mSync) {
                                            if (mToast != null) {
                                                mToast.cancel();
                                            }
                                            mToast = toast;
                                            toast.show();
                                        }
                                    }
                                });
                            }
                        });
//					camera.setPreviewTexture(camera.getSurfaceTexture());
                        if (mPreviewSurface != null) {
                            mPreviewSurface.release();
                            mPreviewSurface = null;
                        }
                        try {
                            camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
                        } catch (final IllegalArgumentException e) {
                            // fallback to YUV mode
                            try {
                                camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE);
                            } catch (final IllegalArgumentException e1) {
                                camera.destroy();
                                return;
                            }
                        }
                        final SurfaceTexture st = mUVCCameraView.getSurfaceTexture();

                        if (st != null) {
                            mPreviewSurface = new Surface(st);
                            camera.setPreviewDisplay(mPreviewSurface);

                            // 设置获取图像帧的回调
                            camera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);

                            // 开启预览
                            camera.startPreview();
                        }
                        synchronized (mSync) {
                            mUVCCamera = camera;
                        }
                    }

                    // 摄像头---红外
                    if (device.getProductId() == 13180 || device.getProductId() == 33291) {
                        final UVCCamera camera = new UVCCamera();
                        camera.open(ctrlBlock);
                        camera.setStatusCallback(new IStatusCallback() {
                            @Override
                            public void onStatus(final int statusClass, final int event, final int selector, final int statusAttribute, final ByteBuffer data) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        final Toast toast = Toast.makeText(MainActivityTexture.this, "onStatus(statusClass=" + statusClass
                                                + "; " +
                                                "event=" + event + "; " +
                                                "selector=" + selector + "; " +
                                                "statusAttribute=" + statusAttribute + "; " +
                                                "data=...)", Toast.LENGTH_SHORT);
                                        synchronized (mSync) {
                                            if (mToast != null) {
                                                mToast.cancel();
                                            }
                                            toast.show();
                                            mToast = toast;
                                        }
                                    }
                                });
                            }
                        });
                        camera.setButtonCallback(new IButtonCallback() {
                            @Override
                            public void onButton(final int button, final int state) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        final Toast toast = Toast.makeText(MainActivityTexture.this, "onButton(button=" + button + "; " +
                                                "state=" + state + ")", Toast.LENGTH_SHORT);
                                        synchronized (mSync) {
                                            if (mToast != null) {
                                                mToast.cancel();
                                            }
                                            mToast = toast;
                                            toast.show();
                                        }
                                    }
                                });
                            }
                        });
//					camera.setPreviewTexture(camera.getSurfaceTexture());
                        if (mPreviewSurfaceInfrared != null) {
                            mPreviewSurfaceInfrared.release();
                            mPreviewSurfaceInfrared = null;
                        }
                        try {
                            camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
                        } catch (final IllegalArgumentException e) {
                            // fallback to YUV mode
                            try {
                                camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE);
                            } catch (final IllegalArgumentException e1) {
                                camera.destroy();
                                return;
                            }
                        }
                        final SurfaceTexture st = mUVCCameraViewInfrared.getSurfaceTexture();

                        if (st != null) {
                            mPreviewSurfaceInfrared = new Surface(st);
                            camera.setPreviewDisplay(mPreviewSurfaceInfrared);

                            // 设置获取图像帧的回调
//                            camera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);

                            // 开启预览
                            camera.startPreview();
                        }
                        synchronized (mSync) {
                            mUVCCameraInfrared = camera;
                        }
                    }
                }
            }, 0);
        }

        @Override
        public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) {

            Log.d(TAG, "onDisconnect: 可见光--断开连接");

            // 设备断开连接，应该检查插入的usb摄像头是不是正确的设备，此处释放摄像头资源
            releaseCamera();
        }

        // USB 摄像头拔出主板
        @Override
        public void onDettach(final UsbDevice device) {
            //Toast.makeText(MainActivityTexture.this, "可见光--拔出", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "onDettach: 可见光--拔出");
            isDettach = true;
        }

        @Override
        public void onCancel(final UsbDevice device) {
            Log.d(TAG, "onCancel: 可见光--cancel");
        }
    };


    /**
     * 释放摄像头资源，同步方法
     */
    private synchronized void releaseCamera() {
        synchronized (mSync) {
            if (mUVCCamera != null) {
                try {
                    mUVCCamera.setStatusCallback(null);
                    mUVCCamera.setButtonCallback(null);
                    mUVCCamera.close();
                    mUVCCamera.destroy();
                } catch (final Exception e) {
                    //
                }
                mUVCCamera = null;
            }
            if (mPreviewSurface != null) {
                mPreviewSurface.release();
                mPreviewSurface = null;
            }

            if (mUVCCameraInfrared != null) {
                try {
                    mUVCCameraInfrared.setStatusCallback(null);
                    mUVCCameraInfrared.setButtonCallback(null);
                    mUVCCameraInfrared.close();
                    mUVCCameraInfrared.destroy();
                } catch (final Exception e) {
                    //
                }
                mUVCCameraInfrared = null;
            }
            if (mPreviewSurfaceInfrared != null) {
                mPreviewSurfaceInfrared.release();
                mPreviewSurfaceInfrared = null;
            }
        }
    }

    // if you need frame data as byte array on Java side, you can use this callback method with UVCCamera#setFrameCallback
    // if you need to create Bitmap in IFrameCallback, please refer following snippet.

    final Bitmap cameraBitmap = Bitmap.createBitmap(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, Bitmap.Config.RGB_565);
    private final IFrameCallback mIFrameCallback = new IFrameCallback() {

        @Override
        public void onFrame(final ByteBuffer frame) {
            frame.clear();
            Log.d(TAG, "onFrame: " + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

            synchronized (cameraBitmap) {
                cameraBitmap.copyPixelsFromBuffer(frame);
            }
            if (isReceived) {
//                    mImageView.post(mUpdateImageTask);
                isReceived = false;
                baos = new ByteArrayOutputStream();
                cameraBitmap.compress(Bitmap.CompressFormat.JPEG, 20, baos);
                picBytes = baos.toByteArray();
                sendPicDataPackage(picBytes);
            }
        }
    };


    private final Runnable mUpdateImageTask = new Runnable() {
        @Override
        public void run() {
            synchronized (cameraBitmap) {
                //图片压缩为 JPEG
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                cameraBitmap.compress(Bitmap.CompressFormat.JPEG, 20, baos);
                byte[] picBytes = baos.toByteArray();
                sendPicDataPackage(picBytes);
            }
        }
    };

    /**
     * 接收服务器的消息
     *
     * @param byteBuf
     */
    @Override
    public void onMessageResponse(ByteBuf byteBuf) {

        //Log.d(TAG, "run: 收到服务器数据时间：" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

        byte[] bytes = byteBuf.array();

        // data.length 原有数据长度，bytes.length 新增数据长度
        byte[] temp = new byte[data.length + byteBuf.readableBytes()];
        // 先将原有数据复制到 中间数组中
        System.arraycopy(data, 0, temp, 0, data.length);
        // 在将新增的数据复制到中间数据中
        System.arraycopy(bytes, 0, temp, data.length, byteBuf.readableBytes());
        // 最终得到数据数组
        data = temp;

        if (data.length > 28) {

            dataLength = ByteBuffer.wrap(ByteUtil.subBytes(data, 4, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();

            // 心跳包
            if (dataLength == 16 && data.length > dataLength + 12 &&
                    0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    1 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()
                    ) {

                Log.d(TAG, "onMessageResponse: 收到心跳包 ");
                data = ByteUtil.subBytes(data, 28, data.length - 28);

                // 没有人脸的返回结果
            } else if (dataLength == 80 && data.length > dataLength + 12 &&
                    0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    0x30 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()
                    ) {
                Log.d(TAG, "onMessageResponse: " + "接收数据---->图片中没有人脸");
                data = ByteUtil.subBytes(data, dataLength + 12, data.length - dataLength - 12);
                isReceived = true;
                // 有人脸的返回结果
            } else {
                Log.d(TAG, "onMessageResponse: " + "接收数据---->有人脸");
                Log.d(TAG, "run: 收到数据包的时间" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                // 当数据长度或等于一个数据包的长度时，才截断出一个完整的数据包
                if (data.length >= dataLength + 12) {

                    //图片字节长度
                    int picLength = ByteBuffer.wrap(ByteUtil.subBytes(data, 348, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();

                    byte[] picByte = ByteUtil.subBytes(data, 352, picLength);

                    receiveBitmap = BitmapFactory.decodeByteArray(picByte, 0, picByte.length);
                    // 抛到UI线程去执行
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mImageView.setImageBitmap(receiveBitmap);
                        }
                    });

                    Log.d(TAG, "onMessageResponse:收到数据包长度 " + data.length);
                    Log.d(TAG, "onMessageResponse 请求头: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 0, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
                    Log.d(TAG, "onMessageResponse: 拼接数据长度 if " + data.length);
                    Log.d(TAG, "onMessageResponse 数据长度: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 4, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 请求类型: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 8, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
                    Log.d(TAG, "onMessageResponse 请求 enumType: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 12, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 请求头 key: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 16, 64)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 请求头结果，“0”代表验证失败,“1”代表验证成功 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 80, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 比对分数 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 84, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat());
                    Log.d(TAG, "onMessageResponse 结果数目 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 88, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());

                    // 截取人员 ID
                    byte[] personIDByte = ByteUtil.subBytes(data, 92, 20);
                    for (int i = 0; i < personIDByte.length; i++) {
                        if (personIDByte[i] == 0) {
                            personIdIndex = i;
                            break;
                        }
                    }
                    Log.d(TAG, "onMessageResponse:人员ID " + new String(ByteUtil.subBytes(personIDByte, 0, personIdIndex)));

                    // 截取人员 姓名
                    byte[] personNameByte = ByteUtil.subBytes(data, 112, 40);
                    for (int i = 0; i < personNameByte.length; i++) {
                        if (personNameByte[i] == 0) {
                            personNameIndex = i;
                            break;
                        }
                    }
                    Log.d(TAG, "onMessageResponse 人员姓名 : " + new String(ByteUtil.subBytes(personNameByte, 0, personNameIndex)));

                    // 时间
                    BigInteger bigInteger = new BigInteger(ByteUtil.subBytes(data, 152, 64));
                    long longValue = bigInteger.longValue();
                    Log.d(TAG, "onMessageResponse 时间: " + DateFormatUtil.format(longValue, DateFormatUtil.DateFormatEnum.ymdhms));
                    Log.d(TAG, "onMessageResponse 点位 : " + ByteUtil.subBytes(data, 216, 128));
                    Log.d(TAG, "onMessageResponse 比对分数 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 344, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat());
                    Log.d(TAG, "onMessageResponse 注册图片长度 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 348, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());

                    data = ByteUtil.subBytes(data, dataLength + 12, data.length - dataLength - 12);

                    isReceived = true;
                }
            }
        }
    }


    /**
     * 和服务器的连接状态发生改变
     *
     * @param statusCode
     */
    @Override
    public void onServiceStatusConnectChanged(int statusCode) {
        Timber.d("connect status:%d", statusCode);
        if (statusCode == NettyListener.STATUS_CONNECT_SUCCESS) {
            //authenticData();
            // 连接成功

        } else if (statusCode == NettyListener.STATUS_CONNECT_CLOSED) {
            // 连接关闭
        } else if (statusCode == NettyListener.STATUS_CONNECT_ERROR) {
            // 连接出错
            WriteLogUtil.writeLogByThread("tcp connect error");
        }
    }

    public class NetworkReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            if (activeNetwork != null) { // connected to the internet
                if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI || activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
                    connect();
                }
            }
        }
    }

    private void connect() {
        if (!NettyClient.getInstance().getConnectStatus()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //连接服务器
                    NettyClient.getInstance().connect();
                }
            }).start();
        }
    }


    /**
     * 发送图片数据包
     */
    public void sendPicDataPackage(final byte[] picBytes) {

        picDataBytes = ArrayMergeUtil.byteMergerAll(

                // 以下三条为请求头部分
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.NET_HEADER_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 表示数据包的长度，只是数据，不包含头
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picBytes.length + 916)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 数据包的类型 0x30
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.DATA_PACKAGE_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                //============================================ 以下为真正的数据包 =================================================================
                // 标识请求的哪一个比对服务
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.ENUM_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 64 字节key，确保请求的唯一性
                //TcpAssembleUtil.assembleRequestKey(),
                ByteUtil.putLong(System.currentTimeMillis(), 0),
                //  20个字节的0
                TcpAssembleUtil.assembleRequestId(),
                // 请求优先级,
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_PRIORITY)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 阈值
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_THRESHOLD)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 最大结果数
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_TOP_X)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 图片的张数
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_PIC_NUM)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 现场图片的长度，需动态计算
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picBytes.length)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(0)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 有几张脸，暂时为 0
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_FACE_COUNT)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 50结构体，每个结构体有4个int
                TcpAssembleUtil.assembleStruct(),

                // 图片数据
                picBytes
        );

        Log.d(TAG, "sendPicDataPackage: 发送数据--->长度为  " + picDataBytes.length);

        NettyClient.getInstance().sendMsgToServer(picDataBytes, new ChannelFutureListener() {    //3
            @Override
            public void operationComplete(ChannelFuture future) {
                if (future.isSuccess()) {                //4
                    Timber.d("Write heartbeat successful");

                } else {
                    Timber.e("Write heartbeat error");
                    WriteLogUtil.writeLogByThread("heartbeat error");
                }
            }
        });

        picDataBytes = null;
    }
}